/*
 * Galaxium Messenger
 * Copyright (C) 2007 Ben Motmans <ben.motmans@gmail.com>
 * Copyright (C) 2007 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Text;
using System.Collections.Generic;

using Gtk;
using Glade;

using Galaxium.Core;
using Galaxium.Gui;
using Galaxium.Gui.GtkGui;

using Mono.Addins;
using Mono.Addins.Setup;
using Anculus.Core;

namespace Galaxium.Client.GtkGui
{
	public class PluginPreferenceWidget : IPreferenceWidget<Widget>
	{
		[Widget("boxList")]
		VBox _boxList = null;
		[Widget("lblVersion")]
		Label _lblVersion = null;
		[Widget("lblLicense")]
		Label _lblLicense = null;
		[Widget("lblAuthors")]
		Label _lblAuthors = null;
		[Widget("lblDescription")]
		Label _lblDescription = null;
		[Widget ("btnInstall")]
		MenuToolButton _btnInstall = null;
		[Widget ("btnRemove")]
		ToolButton _btnRemove = null;
		
		private ListStore _listStore;
		private TreeView _treeView;
		
		private Widget _nativeWidget;
		private Widget _parentLayoutWidget;
		
		private SetupService _addinSetup;
		
		public void Initialize ()
		{
			_nativeWidget = GladeUtility.ExtractWidget<Widget> (GladeUtility.GetGladeResourceStream (typeof (PluginPreferenceWidget).Assembly, "PluginPreferenceWidget.glade"), "widget", this);
			
			_listStore = new ListStore(typeof(bool), typeof(bool), typeof(string), typeof(Addin));
			_treeView = new TreeView();
			_treeView.Model = _listStore;
			
			CellRendererToggle toggleRenderer = new CellRendererToggle ();
			toggleRenderer.Activatable = true;
			toggleRenderer.Toggled += new ToggledHandler (ItemToggled);
			
			CellRendererText nameRenderer = new CellRendererText ();
			nameRenderer.Weight = 900;
			
			TreeViewColumn nameColumn = new TreeViewColumn();
			nameColumn.Title = "Name";
			nameColumn.PackStart (nameRenderer, true);
			nameColumn.AddAttribute (nameRenderer, "text", 2);
			
			ScrolledWindow window = new ScrolledWindow();
			window.ShadowType = ShadowType.In;
			window.Add(_treeView);
			
			TreeViewColumn toggleColumn = new TreeViewColumn();
			toggleColumn.Title = "Active";
			toggleColumn.PackStart (toggleRenderer, true);
			toggleColumn.AddAttribute (toggleRenderer, "active", 0);
			toggleColumn.AddAttribute (toggleRenderer, "inconsistent", 1);

			_treeView.AppendColumn (toggleColumn);
			_treeView.AppendColumn (nameColumn);
			
			_treeView.Selection.Mode = SelectionMode.Single;
			_treeView.Selection.Changed += new EventHandler (TreeSelectionChanged);
			
			_addinSetup = new SetupService();
			
			PopulateList ();
			
			TreeIter iter;
			if (_listStore.GetIterFirst (out iter)) {
				TreePath path = _listStore.GetPath (iter);
				_treeView.SetCursor (path, nameColumn, false);
			}

			_listStore.SetSortFunc (1, new TreeIterCompareFunc (SortTextFunc));
			_listStore.SetSortColumnId (1, SortType.Ascending);
			
			_boxList.Add(window);
			
			Menu btnInstallMenu = new Menu ();
			
			ImageMenuItem menuItem = new ImageMenuItem ("From File");
			menuItem.Image = Image.NewFromIconName ("gtk-open", IconSize.Menu);
			menuItem.Activated += InstallFileClicked;
			btnInstallMenu.Add (menuItem);
			
			menuItem = new ImageMenuItem ("From Internet");
			menuItem.Image = Image.NewFromIconName ("gtk-down", IconSize.Menu);
			menuItem.Sensitive = false;
			menuItem.Activated += InstallInternetClicked;
			btnInstallMenu.Add (menuItem);
			
			btnInstallMenu.ShowAll ();
			_btnInstall.Menu = btnInstallMenu;
			
			_nativeWidget.ShowAll ();
		}

		public Widget NativeWidget
		{
			get { return _nativeWidget; }
		}
		
		void PopulateList ()
		{
			//TODO: visually show plugins with load errors
			
			_listStore.Clear ();
			
			foreach (Addin addin in AddinManager.Registry.GetAddins())
			{
				string[] categories = addin.Description.Category.Split (',');
				
				// Don't display addins in the 'core' category
				if (Array.IndexOf (categories, "core") == -1)
					_listStore.AppendValues (addin.Enabled, false, addin.Name, addin);
			}
		}
		
		private int SortTextFunc (TreeModel model, TreeIter iter1, TreeIter iter2)
		{
			string name1 = model.GetValue (iter1, 2) as string;
			string name2 = model.GetValue (iter2, 2) as string;
		
			if (name1 == null && name2 == null) return 0;
			else if (name1 == null) return -1;
			else if (name2 == null) return 1;

			return name1.CompareTo (name2);
		}
		
#region Event Handlers
		private void TreeSelectionChanged (object sender, EventArgs args)
		{
			TreeIter iter;
			if (_treeView.Selection.GetSelected (out iter)) {
				Addin addin = _listStore.GetValue(iter, 3) as Addin;
								
				_lblVersion.Text = addin.Version.ToString();
				_lblLicense.Text = addin.Description.Copyright;
				_lblAuthors.Text = addin.Description.Author;
				_lblDescription.Text = addin.Description.Description;
				
				_btnRemove.Sensitive = addin.AddinFile.StartsWith (CoreUtility.AddinConfigurationDirectory);
			} else {
				_lblVersion.Text = String.Empty;
				_lblLicense.Text = String.Empty;
				_lblAuthors.Text = String.Empty;
				_lblDescription.Text = String.Empty;
				
				_btnRemove.Sensitive = false;
			}
		}
		
		private void ItemToggled (object sender, ToggledArgs args)
		{
	 		TreeIter iter;
			if (_listStore.GetIterFromString (out iter, args.Path)) {
	 			bool val = (bool) _listStore.GetValue (iter, 0);
	 			_listStore.SetValue (iter, 0, !val);
				
				Addin addin = _listStore.GetValue(iter, 3) as Addin;
				addin.Enabled = !val;
	 		}
		}
		
		void InstallFileClicked (object sender, EventArgs args)
		{
			FileChooserDialog dialog = new FileChooserDialog ("Select Addin", null, FileChooserAction.Open, "Cancel", ResponseType.Cancel, "Select", ResponseType.Accept);
			FileFilter filter = new FileFilter ();
			filter.AddPattern ("*.mpack");
			dialog.Filter = filter;
			dialog.SetCurrentFolder (Environment.GetFolderPath (Environment.SpecialFolder.Personal));
			
			if (dialog.Run () == (int)ResponseType.Accept)
			{
				try
				{
					if (!AddinUtility.SetupService.Install (new ConsoleProgressStatus (true), dialog.Filenames))
						throw new ApplicationException ("Unknown installation failure");
					
					PopulateList ();
				}
				catch (Exception ex)
				{
					MessageDialog errdialog = new MessageDialog (_nativeWidget.Toplevel as Gtk.Window,
					                                             DialogFlags.Modal, MessageType.Error, ButtonsType.Ok,
					                                             "The addin failed to install\n\n" + ex.Message);
					
					errdialog.Run ();
					errdialog.Destroy ();
				}
			}
			
			dialog.Destroy();
		}
		
		void InstallInternetClicked (object sender, EventArgs args)
		{
		}
#endregion
		
#region Glade Event Handlers
		void btnInstallClicked (object sender, EventArgs args)
		{
			InstallFileClicked (sender, args);
		}
		
		void btnRemoveClicked (object sender, EventArgs args)
		{
			TreeIter iter;
			if (_treeView.Selection.GetSelected (out iter))
			{
				Addin addin = _listStore.GetValue (iter, 3) as Addin;
				
				try
				{
					AddinUtility.SetupService.Uninstall (new ConsoleProgressStatus (true), addin.Id);
					
					PopulateList ();
				}
				catch (Exception ex)
				{
					MessageDialog errdialog = new MessageDialog (_nativeWidget.Toplevel as Gtk.Window,
					                                             DialogFlags.Modal, MessageType.Error, ButtonsType.Ok,
					                                             "The addin failed to uninstall\n\n" + ex.Message);
					
					errdialog.Run ();
					errdialog.Destroy ();
				}
			}
			else
				Log.Error ("Unable to retrieve addin");
		}
#endregion
	}
}